import 'dart:async';
import 'dart:convert';
import 'dart:io';

import 'package:http/http.dart' as http;
import 'package:http/io_client.dart';

import '../common/test_page.dart';


class TestClient extends http.BaseClient {
  @override
  Future<http.StreamedResponse> send(http.BaseRequest request) {
    throw UnimplementedError();
  }
}

class TestClient2 extends http.BaseClient {
  @override
  Future<http.StreamedResponse> send(http.BaseRequest request) {
    throw UnimplementedError();
  }
}

http.Client getClient() {
  var ioClient = HttpClient()
    ..badCertificateCallback = (X509Certificate cert, String host, int port) => true;
  http.Client client = IOClient(ioClient);
  return client;
}

class IoTestPage extends TestPage {
  IoTestPage(super.title) {
    test('使用无效URL发送http.Client().send(http.StreamedRequest("POST", Uri.http("http.invalid", "")))', () {
      var client = http.Client();
      var url = Uri.http('http.invalid', '');
      var request = http.StreamedRequest('POST', url);
      request.headers[HttpHeaders.contentTypeHeader] =
      'application/json; charset=utf-8';

      expect(
          client.send(request),
          ''
      );

      request.sink.add('{"hello": "world"}'.codeUnits);
      request.sink.close();
    });

    test('http.runWithClient(http.Client.new, TestClient.new)', () {
      final client = http.runWithClient(http.Client.new, TestClient.new);
      expect(client, '');
    });

    test('http.runWithClient(http.Client.new, http.Client.new)', () {
      final client = http.runWithClient(http.Client.new, http.Client.new);
      expect(client, '');
    });

    test('http.runWithClient(() {http.runWithClient(() => nestedClient = http.Client(), TestClient2.new);client = http.Client();}, TestClient.new)', () {
      late final http.Client client;
      late final http.Client nestedClient;
      http.runWithClient(() {
        http.runWithClient(() => nestedClient = http.Client(), TestClient2.new);
        client = http.Client();
      }, TestClient.new);
      expect(client, '');
      expect(nestedClient, '');
    });

    test('http.runWithClient(() {http.runWithClient(http.Client.new, http.Client.new);}, http.Client.new)', () {
      http.runWithClient(() {
        http.runWithClient(http.Client.new, http.Client.new);
      }, http.Client.new);
    });

    group('http.head()', () {
      test('head', () async {
        var response = await getClient().head(Uri.parse('https://httpbun.com/'));
        expect(response.statusCode, 200);
        expect(response.body, '');
      });

      test('http.runWithClient(() => http.head(), TestClient.new)', () {
        expect(
                () => http.runWithClient(() => getClient().head(Uri.parse('https://httpbun.com/')), TestClient.new),
            '');
      });

      test('http.get(Uri url, {Map<String, String>? headers})', () async {
        var response = await getClient().get(Uri.parse('https://httpbun.com/'), headers: {
          'X-Random-Header': 'Value',
          'X-Other-Header': 'Other Value',
          'User-Agent': 'Dart'
        });
        expect(response.statusCode, 200);
        expect(
            response.body,
            '');
      });

      test('http.runWithClient(() => http.get(), TestClient.new)', () {
        expect(
                () => http.runWithClient(() => getClient().get(Uri.parse('https://httpbun.com/')), TestClient.new),
            '');
      });

      test('http.post(Uri url, {Map<String, String>? headers})', () async {
        var response = await getClient().post(Uri.parse('https://httpbun.com/'), headers: {
          'X-Random-Header': 'Value',
          'X-Other-Header': 'Other Value',
          'Content-Type': 'text/plain',
          'User-Agent': 'Dart'
        });
        expect(response.statusCode, 200);
        expect(
            response.body,
            '');
      });

      test('http.post(Uri url, {Map<String, String>? headers, Object? body}) 内容为字符串', () async {
        var response = await getClient().post(Uri.parse('https://httpbun.com/'),
            headers: {
              'X-Random-Header': 'Value',
              'X-Other-Header': 'Other Value',
              'User-Agent': 'Dart'
            },
            body: 'request body');
        expect(response.statusCode, 200);
        expect(
            response.body,
            '');
      });

      test('http.post(Uri url, {Map<String, String>? headers, Object? body}) 内容为字节型', () async {
        var response = await getClient().post(Uri.parse('https://httpbun.com/'), headers: {
          'X-Random-Header': 'Value',
          'X-Other-Header': 'Other Value',
          'User-Agent': 'Dart'
        }, body: [
          104,
          101,
          108,
          108,
          111
        ]);
        expect(response.statusCode, 200);
        expect(
            response.body,
            '');
      });

      test('http.post(Uri url, {Map<String, String>? headers, Object? body}) 内容为带有字段的map', () async {
        var response = await getClient().post(Uri.parse('https://httpbun.com/'), headers: {
          'X-Random-Header': 'Value',
          'X-Other-Header': 'Other Value',
          'User-Agent': 'Dart'
        }, body: {
          'some-field': 'value',
          'other-field': 'other value'
        });
        expect(response.statusCode, 200);
        expect(
            response.body,
            '');
      });

      test('http.runWithClient(() => http.post(Uri, body: "testing"), TestClient.new)', () {
        expect(
                () => http.runWithClient(
                    () => http.post(Uri.parse('https://httpbun.com/'), body: 'testing'), TestClient.new),
            '');
      });

      test('http.put(Uri url,{Map<String, String>? headers})', () async {
        var response = await getClient().put(Uri.parse('https://httpbun.com/'), headers: {
          'X-Random-Header': 'Value',
          'X-Other-Header': 'Other Value',
          'Content-Type': 'text/plain',
          'User-Agent': 'Dart'
        });
        expect(response.statusCode, 200);
        expect(
            response.body,
            '');
      });

      test('http.put(Uri url,{Map<String, String>? headers, Object? body}) body为字符串', () async {
        var response = await getClient().put(Uri.parse('https://httpbun.com/'),
            headers: {
              'X-Random-Header': 'Value',
              'X-Other-Header': 'Other Value',
              'User-Agent': 'Dart'
            },
            body: 'request body');
        expect(response.statusCode, 200);
        expect(
            response.body,
            '');
      });

      test('http.put(Uri url,{Map<String, String>? headers, Object? body}) body为字节型', () async {
        var response = await getClient().put(Uri.parse('https://httpbun.com/'), headers: {
          'X-Random-Header': 'Value',
          'X-Other-Header': 'Other Value',
          'User-Agent': 'Dart'
        }, body: [
          104,
          101,
          108,
          108,
          111
        ]);
        expect(response.statusCode, 200);
        expect(
            response.body,
            '');
      });

      test('http.put(Uri url,{Map<String, String>? headers, Object? body}) body为带有字段的map', () async {
        var response = await getClient().put(Uri.parse('https://httpbun.com/'), headers: {
          'X-Random-Header': 'Value',
          'X-Other-Header': 'Other Value',
          'User-Agent': 'Dart'
        }, body: {
          'some-field': 'value',
          'other-field': 'other value'
        });
        expect(response.statusCode, 200);
        expect(
            response.body,
            '');
      });

      test('http.runWithClient(() => http.put(Uri, body: "testing"), TestClient.new)', () {
        expect(
                () => http.runWithClient(
                    () => getClient().put(Uri.parse('https://httpbun.com/'), body: 'testing'), TestClient.new),
            '');
      });

      test('http.patch((Uri url,{Map<String, String>? headers}))', () async {
        var response = await getClient().patch(Uri.parse('https://httpbun.com/'), headers: {
          'X-Random-Header': 'Value',
          'X-Other-Header': 'Other Value',
          'Content-Type': 'text/plain',
          'User-Agent': 'Dart'
        });
        expect(response.statusCode, 200);
        expect(
            response.body,
            '');
      });

      test('http.patch((Uri url,{Map<String, String>? headers, Object? body})) body为字符串', () async {
        var response = await getClient().patch(Uri.parse('https://httpbun.com/'),
            headers: {
              'X-Random-Header': 'Value',
              'X-Other-Header': 'Other Value',
              'User-Agent': 'Dart'
            },
            body: 'request body');
        expect(response.statusCode, 200);
        expect(
            response.body,
            '');
      });

      test('http.patch((Uri url,{Map<String, String>? headers, Object? body})) body为字节型', () async {
        var response = await getClient().patch(Uri.parse('https://httpbun.com/'), headers: {
          'X-Random-Header': 'Value',
          'X-Other-Header': 'Other Value',
          'User-Agent': 'Dart'
        }, body: [
          104,
          101,
          108,
          108,
          111
        ]);
        expect(response.statusCode, 200);
        expect(
            response.body,
            '');
      });

      test('http.patch((Uri url,{Map<String, String>? headers, Object? body})) body为带字段的map', () async {
        var response = await getClient().patch(Uri.parse('https://httpbun.com/'), headers: {
          'X-Random-Header': 'Value',
          'X-Other-Header': 'Other Value',
          'User-Agent': 'Dart'
        }, body: {
          'some-field': 'value',
          'other-field': 'other value'
        });
        expect(response.statusCode, 200);
        expect(
            response.body,
            '');
      });

      test('http.delete(Uri url,{Map<String, String>? headers})', () async {
        var response = await getClient().delete(Uri.parse('https://httpbun.com/'), headers: {
          'X-Random-Header': 'Value',
          'X-Other-Header': 'Other Value',
          'User-Agent': 'Dart'
        });
        expect(response.statusCode, 200);
        expect(
            response.body,
            '');
      });

      test('http.runWithClient(() => http.patch(Uri, body: "testing"), TestClient.new)', () {
        expect(
                () => http.runWithClient(
                    () => getClient().patch(Uri.parse('https://httpbun.com/'), body: 'testing'), TestClient.new),
            '');
      });

      test('http.read(Uri url, {Map<String, String>? headers}) => _withClient((client) => client.read(url, headers: headers))', () async {
        var response = await getClient().read(Uri.parse('https://httpbun.com/'), headers: {
          'X-Random-Header': 'Value',
          'X-Other-Header': 'Other Value',
          'User-Agent': 'Dart'
        });
        expect(
            response,
            '');
      });

      test('http.read(Uri.resolve("/error"))', () {
        expect(getClient().read(Uri.parse('https://httpbun.com/').resolve('/error')), '');
      });

      test('http.runWithClient(() => http.read(), TestClient.new)', () {
        expect(
                () => http.runWithClient(() => getClient().read(Uri.parse('https://httpbun.com/')), TestClient.new),
            '');
      });

      test('http.readBytes(Uri url, {Map<String, String>? headers}) =>_withClient((client) => client.readBytes(url, headers: headers))', () async {
        var bytes = await getClient().readBytes(Uri.parse('https://httpbun.com/'), headers: {
          'X-Random-Header': 'Value',
          'X-Other-Header': 'Other Value',
          'User-Agent': 'Dart'
        });

        expect(
            String.fromCharCodes(bytes),
            '');
      });

      test('http.readBytes(Uri.resolve("/error"))', () {
        expect(
            getClient().readBytes(Uri.parse('https://httpbun.com/').resolve('/error')), '');
      });

      test('http.runWithClient(() => http.readBytes(), TestClient.new)', () {
        expect(
                () => http.runWithClient(
                    () => getClient().readBytes(Uri.parse('https://httpbun.com/')), TestClient.new),
            '');
      });
    });

    test('http.MultipartRequest使用磁盘中的文件', () async {
      var file = http.MultipartFile.fromString('file', 'Hello World!!!');
      var request = http.MultipartRequest('POST', Uri.parse('https://httpbun.com/'));
      request.files.add(file);

      expect(request, '');
    });

    test('http.Request("GET", uri)', () async {
      final request = http.Request('GET', Uri.parse('https://httpbun.com/'))
        ..body = 'hello'
        ..headers['User-Agent'] = 'Dart';

      final response = await send(request);

      expect(response.statusCode, 200);
      final bytesString = await response.stream.bytesToString();
      expect(
          bytesString,
          '');
    });

    test('http.Request()没有重定向', () async {
      final request = http.Request('GET', Uri.parse('https://httpbun.com/').resolve('/redirect'))
        ..followRedirects = false;
      final response = await send(request);

      expect(response.statusCode, 302);
    });

    test('http.Request()重定向', () async {
      final request = http.Request('GET', Uri.parse('https://httpbun.com/').resolve('/redirect'));
      final response = await send(request);

      expect(response.statusCode, 200);
      final bytesString = await response.stream.bytesToString();
      expect(bytesString, '');
    });

    test('http.Request()超过最大重定向次数', () async {
      final request = http.Request('GET', Uri.parse('https://httpbun.com/').resolve('/loop?1'))
        ..maxRedirects = 2;
      expect(
          send(request),
          '');
    });

    group('内容长度', () {
      test('http.StreamedRequest()..contentLength控制内容长度标头', () async {
        var request = http.StreamedRequest('POST', Uri.parse('https://httpbun.com/'))
          ..contentLength = 10
          ..sink.add([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
        request.sink.close();
        var response = await send(request);
        expect(
            await utf8.decodeStream(response.stream),
            '');
      });

      test('http.StreamedRequest()默认不发送内容长度', () async {
        var request = http.StreamedRequest('POST', Uri.parse('https://httpbun.com/'));
        request.sink.add([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
        request.sink.close();
        var response = await send(request);
        expect(await utf8.decodeStream(response.stream), '');
      });
    });

    test('http.StreamedRequest().send()带有一个没有内容长度的响应', () async {
      var request = http.StreamedRequest('GET', Uri.parse('https://httpbun.com/').resolve('/no-content-length'));
      request.sink.close();
      var response = await send(request);
      expect(await utf8.decodeStream(response.stream), 'body');
    });

  }

  Future<http.StreamedResponse> send(http.BaseRequest request) async {
    var client = getClient();

    try {
      var response = await client.send(request);
      var stream = onDone(response.stream, client.close);
      return http.StreamedResponse(http.ByteStream(stream), response.statusCode,
          contentLength: response.contentLength,
          request: response.request,
          headers: response.headers,
          isRedirect: response.isRedirect,
          persistentConnection: response.persistentConnection,
          reasonPhrase: response.reasonPhrase);
    } catch (_) {
      client.close();
      rethrow;
    }
  }

  Stream<T> onDone<T>(Stream<T> stream, void Function() onDone) =>
      stream.transform(StreamTransformer.fromHandlers(handleDone: (sink) {
        sink.close();
        onDone();
      }));
}
